#include"videooutput.h"
#include<thread>

VideoOutput::VideoOutput(AVSync* avsync, AVRational time_base, AVFrameQueue* frame_queue, int video_width, int video_height){
    this->avsync = avsync;
    this->time_base = time_base;
    this->frame_queue = frame_queue;
    this->video_width = video_width;
    this->video_height = video_height;
}

VideoOutput::~VideoOutput(){

}

int VideoOutput::Init(){
    if(SDL_Init(SDL_INIT_VIDEO)){
        return -1;
    }
    win = SDL_CreateWindow("player", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, video_width, video_height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
    if(!win){
        return -1;
    }

    renderer = SDL_CreateRenderer(win, -1, 0);
    if(!renderer){
        return -1;
    }

    texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, video_width, video_height);
    if(!texture){
        return -1;
    }

    yuv_buf_size = video_width * video_height * 1.5;
    yuv_buf = new uint8_t[yuv_buf_size];
}

int VideoOutput::MainLoop(){
    SDL_Event event;
    while (true)
    {
        RefreshLoopWaitEvent(&event);
        switch (event.type){
        case SDL_KEYDOWN:
            if(event.key.keysym.sym == SDLK_ESCAPE){
                return 0;
            }
            break;
        case SDL_QUIT:
            return 0;
        default:
            break;
        }
    }
    return 0;
}

#define REFRESH_RATE 0.01
void VideoOutput::RefreshLoopWaitEvent(SDL_Event* event){
    double remaining_time = 0.0;
    SDL_PumpEvents();
    while (!SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)){
        if(remaining_time > 0.0){
            this_thread::sleep_for(chrono::milliseconds(int64_t(remaining_time * 1000.0)));
        }
        remaining_time = REFRESH_RATE;
        videoRefresh(&remaining_time);
        SDL_PumpEvents();
    }   
}

void VideoOutput::videoRefresh(double* remaining_time){
    AVFrame* frame = nullptr;
    frame = frame_queue->Front();
    if(frame){
        double pts = frame->pts * av_q2d(time_base);
        double diff = pts - avsync->GetClock();
        if(diff > 0){
            *remaining_time = FFMIN(*remaining_time, diff);
            return;
        }
        rect.x = 0;
        rect.y = 0;
        rect.w = video_width;
        rect.h = video_height;
        SDL_UpdateTexture(texture, &rect, frame->data[0], frame->linesize[0],
                          frame->data[1], frame->linesize[1],
                          frame->data[2], frame->linesize[2]);
        SDL_RenderClear(renderer);
        SDL_RenderCopy(renderer, texture, NULL, &rect);
        SDL_RenderPresent(renderer);
        frame = frame_queue->Pop(1);
        av_frame_free(&frame);
    }
}